/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef TUSB_OSAL_PONY_H
#define TUSB_OSAL_PONY_H

/* includes (standard library, system) ---------------------------------------*/
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <kal.h>
#include <a_atomic.h>
/* includes (local) ----------------------------------------------------------*/

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/

//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
{
    k_task_msleep(msec);
}

//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
typedef struct {
    atomic_int flag;
} osal_spinlock_t;

#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name

TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx)
{
    atomic_int_set(&ctx->flag, 0);
}

TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr)
{
    if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
        return;   // single core MCU does not need to lock in ISR
    }
    while (atomic_int_set_eq(&ctx->flag, 0, 1)) {
    }
}

TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr)
{
    if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
        return;   // single core MCU does not need to lock in ISR
    }
    atomic_int_set(&ctx->flag, 0);
}

//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+
typedef k_sem_t osal_semaphore_def_t;
typedef k_sem_t *osal_semaphore_t;

TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t
osal_semaphore_create(osal_semaphore_def_t *semdef)
{
    if (k_mutex_init(semdef) != 0) {
        return NULL;
    }
    return semdef;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl)
{
    return k_sem_destroy(semd_hdl) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
    (void)in_isr;
    return k_sem_post(sem_hdl) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl,
                                                             uint32_t msec)
{
    return k_sem_timedwait(sem_hdl, k_ms2tick(msec)) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
{
    // Not supported
}

//--------------------------------------------------------------------+
// MUTEX API (priority inheritance)
//--------------------------------------------------------------------+
typedef k_mutex_t osal_mutex_def_t;
typedef k_mutex_t *osal_mutex_t;

TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef)
{
    if (k_mutex_init(mdef) != 0) {
        return NULL;
    }
    return mdef;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl)
{
    return k_mutex_destroy(mutex_hdl) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
{
    return k_mutex_timedlock(mutex_hdl, k_ms2tick(msec)) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
    return k_mutex_unlock(mutex_hdl) == 0;
}

//--------------------------------------------------------------------+
// QUEUE API
//--------------------------------------------------------------------+

// role device/host is used by OS NONE for mutex (disable usb isr) only
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type)                                             \
    osal_queue_def_t _name = {.depth = _depth, .item_sz = sizeof(_type)};

typedef struct {
    uint16_t depth;
    uint16_t item_sz;
    k_mq_t mq;
} osal_queue_def_t;

typedef osal_queue_def_t *osal_queue_t;

TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef)
{
    if (k_mq_create(&(qdef->mq), "tusb", qdef->item_sz, qdef->depth, 0) != 0) {
        return NULL;
    }
    return qdef;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl)
{
    return k_mq_delete(&(qhdl->mq)) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data,
                                                            uint32_t msec)
{
    return k_mq_timedrecv(&(qhdl->mq), data, qhdl->item_sz, k_ms2tick(msec)) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data,
                                                         bool in_isr)
{
    (void)in_isr;
    return k_mq_send(&(qhdl->mq), data, qhdl->item_sz) == 0;
}

TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
    return true;   // Not supported
}

/* externs -------------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* TUSB_OSAL_PONY_H */
